/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package GUI.XML;

import TDAMapeo.Entry;
import TDAPila.ArrayStack;
import java.net.URI;
import TDAPila.EmptyStackException;
import java.io.*;

/**
 * Permite generar archivos XML que se procesan en memoria para luego escribirlos en el disco o en la consola
 * @author Caneva Francisco
 * @author Holtz Jordan
 */
public class XMLWriter {
    /**
     * Cola que almacena las etiquetas abiertas
     */
    private ArrayStack<String> tagStack;
    /**
     * Contenido en memoria del XML en forma de {@link String}.
     */
    private String xmlContent;
    /**
     * Indicador de que el XML ya se cerr&oacute; (las instancias de esta clase no
     * pueden ser reusadas una vez cerradas)
     */
    private boolean closed;
    /**
     * Indicador para tabular con espacios o con tabuladores ("\t")
     */
    private boolean tabWithSpaces;
    
    /**
     * Crea un objeto XMLWriter
     * @param t True para tabular con espacios, false para tabular con tabuladores
     */
    public XMLWriter(boolean t) {
        tagStack = new ArrayStack<String>();
        xmlContent = "";
        closed = false;
        tabWithSpaces = t;
    }
    
    /**
     * Abre una seccion del tipo <code>&lt;seccion&gt;</code>
     * @param name Nombre de la seccion
     */
    public void openSection(String name) {
        if (!closed) {
            openSection(name, null);
        }
    }
    
    /**
     * Abre una seccion del tipo <code>&lt;seccion&gt;</code>
     * @param name
     * @param params
     */
    public void openSection(String name, Entry<String, String>[] params) {
        if (!closed) {
            String openTag = "<" + URI.create(name);
            if (params != null) {
                for (int i = 0; i < params.length; i++) {
                    openTag += " " + URI.create(params[i].getKey())
                            + "=" + URI.create(params[i].getValue());
                }
            }
            openTag += ">";
            xmlContent += getIndent() + openTag + "\n";
            tagStack.push(name);
        }
    }
    
    public void lineSection(String name, String data) {
        if (!closed) {
            lineSection(name, null, data);
        }
    }
    
    public void lineSection(String name, Entry<String, String>[] params, String data) {
        if (!closed) {
            String openTag = "<" + URI.create(name);
            if (params!=null) {
                for (int i = 0; i < params.length; i++) {
                    openTag += " " + URI.create(params[i].getKey())
                            + "=\"" + URI.create(params[i].getValue()) + "\"";
                }
            }
            openTag += ">";
            String closeTag = "</" + URI.create(name) + ">";
            xmlContent += getIndent() + openTag + data + closeTag + "\n";
        }
    }
    
    public void autoCloseSection(String name) {
        if (!closed) {
            autoCloseSection(name, null);
        }
    }
    
    public void autoCloseSection(String name, Entry<String, String>[] params) {
        if (!closed) {
            String openTag = "<" + URI.create(name);
            if (params!=null) {
                for (int i = 0; i < params.length; i++) {
                    openTag += " " + URI.create(params[i].getKey())
                            + "=\"" + URI.create(params[i].getValue()) + "\"";
                }
            }
            openTag += " />";
            xmlContent += getIndent() + openTag + "\n";
        }
    }
    
    /**
     * Cierra la ultima seccion abierta por {@link XMLWriter#openSection(String) openSection}
     */
    public void closeLastOpenedSection() throws EmptyStackException {
        String closeTag = "</"+URI.create(tagStack.pop()) + ">";
        xmlContent += getIndent() + closeTag + "\n";
    }

    /**
     * Obtiene la indentaci&oacute;n necesaria del rengl&oacute;n para mejorar su visualizaci&oacute;n
     * @return Un {@link String String} con los espacios necesarios para indentar
     */
    private String getIndent() {
        String indent = "";
        for (int i = 0; i < tagStack.size(); i++) {
            indent += tabWithSpaces? " ": "\t";
        }
        return indent;
    }

    /**
     * Consulta acerca de si el XML se encuentra cerrado o no
     * @return <b>True</b> si est&acute; cerrado, <b>false</b> caso contrario
     */
    public boolean isClosed() {
        return closed;
    }

    /**
     * Cierra el XML para completar su sintaxis y su contenido
     */
    public void closeXML() {
        if(!isClosed()) {
            while(!tagStack.isEmpty()) {
                try {
                    closeLastOpenedSection();
                }
                catch (EmptyStackException ex) {
                    //Punto no alcanzable en ejecuccion
                }
            }
        }
    }

    /**
     * Verifica que el XML este completamente construido y retorna un {@link String String} con el contenido del XML.
     * @return El XML procesado
     */
    public String getXMLString() {
        if(!isClosed()) {
            closeXML();
        }
        return xmlContent;
    }

    /**
     * Vuelca el contenido del XML a un archivo especificado
     * @param address Direccion donde se escribe el archivo
     */
    public void dumpToFile(String address) throws IOException {
        if(!isClosed()) {
        	closeXML();
        }
        File output = new File(address);
        FileWriter fw = new FileWriter(output);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.append(xmlContent);
        bw.flush();
        bw.close();
    }

}